/******************************************************************************
 * trace.c
 * 
 * Main source file for multi-level tracing. The functions defined here are
 * called via macros defined in trace.h.
 * 
 * Copyright (c) 1999, K A Fraser.
 */

#include "trace.h"
#include <stdarg.h>
#include <time.h>
#include "defines.h"

#ifdef USE_PTH
#include <pth.h>
#endif

#include <stdio.h>

static FILE *fp = 0;

/******************************************************************************
 * trc_init:
 *   Initialise tracing.
 */
void trc_init(void)
{
    if ( (fp = fopen("/local/scratch/kaf24/out.trc", "wb")) == NULL )
    {
        fprintf(stderr, 
                "Couldn't open trace file -- going for /dev/null...\n");
        if ( (fp = fopen("/dev/null", "wb")) == NULL )
        {
            fprintf(stderr,
                    "Couldn't get /dev/null either!\n");
            exit(1);
        }
    }
}


/******************************************************************************
 * trc_close:
 *   Close down tracing.
 */
void trc_close(void)
{
    if ( fp )
    {
        fclose(fp);
        fp = NULL;
    }
}


/******************************************************************************
 * trc_trace:
 *   Output a line of tracing.
 */
void trc_trace(int level, char *file, char *func, int line, char *fmt, ...)
{
    va_list    args;
    time_t     t;
    struct tm *tm;
    char formatstring[200];

    static time_t old_time = 0;
    static char   ts[10]   = "";

    /* Reformat the time if it has changed. */
    if ( (t = time(NULL)) != old_time )
    {
        struct tm *tm = localtime(&t);
        old_time = t;
        sprintf(ts, "%2.0d:%2.2d:%2.2d", tm->tm_hour, tm->tm_min, tm->tm_sec);
    }

    /* Dump out the time and place of the trace. */
    fprintf(fp, "%s %.16s %.16s %3.0d ", ts, file, func, line);

    /* Dump out the trace level. */
    switch ( level )
    {
    case LEVEL_ASSERT: fprintf(fp, "ASS "); break;
    case LEVEL_ERROR:  fprintf(fp, "ERR "); break;
    case LEVEL_WARN:   fprintf(fp, "WRN "); break;
    case LEVEL_NORMAL: fprintf(fp, "... "); break;
    default:           fprintf(fp, "??? "); break;
    }

    /* Dump out the trace text. */
    va_start(args, fmt);
    vsprintf(formatstring, fmt, args);
    fprintf(fp, formatstring);
    fputc('\n', fp);

    /* Important trace messages are echoed directly to the user! */
    if ( level == LEVEL_ERROR )
    {
        fprintf(stderr, "ERROR (file:%s func:%s line:%d) -- ", 
                file, func, line);
        fprintf(stderr, formatstring);
        fputc('\n', stderr);
    }
    else if ( level == LEVEL_ASSERT )
    {
        fprintf(stderr, "ASSERTION (file:%s func:%s line %d) -- ",
                file, func, line);
        fprintf(stderr, formatstring);
        fputc('\n', fp);
        *((int*)0) = 0; // force a core dump for debugging purposes
    }

    va_end(args);
}
